package com.yanqu.road.server.manager.tomb;

import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.union.activitygroup.UnionActivityGroup;
import com.yanqu.road.logic.activity.tomb.config.entity.ActivityTombFloor;
import com.yanqu.road.logic.activity.tomb.config.entity.ActivityTombRank;
import com.yanqu.road.logic.activity.tomb.config.entity.EventInfo;
import com.yanqu.road.pb.tomb.Tomb;

import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.logic.activity.tomb.config.TombConfig;
import com.yanqu.road.logic.activity.tomb.config.entity.ActivityTombEvent;
import com.yanqu.road.server.manager.tomb.astar.AStarMaze;
import com.yanqu.road.server.manager.tomb.astar.Coordinate;
import com.yanqu.road.server.manager.tomb.entity.*;
import com.yanqu.road.server.manager.tomb.event.*;
import com.yanqu.road.server.manager.union.activitygroup.Cross2UnionActivityGroupMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import io.netty.util.internal.StringUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TombMaze {
    private static Logger logger = LogManager.getLogger(TombMaze.class.getName());

    private DbTombMaze dbTombMaze;

    private TombActivity activity;

    private int floor;

    private Map<String, Position> positionMap = new ConcurrentHashMap<>();

    private Map<String, Position> buffEventMap = new HashMap<>();

    private Map<Integer, IEvent> iEventMap = new HashMap<>();


    private Map<String, Set<String>> pathAreaMap = new ConcurrentHashMap<>();

    private final Lock pathMergeLock = new ReentrantLock();

    private final Map<Integer, Lock> positionLockMap = new ConcurrentHashMap<>();

    TombMaze(DbTombMaze dbTombMaze, TombActivity activity) {
        this.dbTombMaze = dbTombMaze;
        this.activity = activity;
        String[][] grid = this.dbTombMaze.getMaze().getsGrip();
        try {
            for (int row = 0; row < grid.length; row++) {
                for (int column = 0; column < grid[row].length; column++) {
                    Position position = new Position(row, column);
                    position.parseString(grid[position.getRow()][position.getColumn()]);
                    if (StringUtil.isNullOrEmpty(position.getpRelation())) {
//                        if (position.canStand()) {
//                            continue;
//                        }
                    }

                    position.refreshTimestamp();
                    if (position.getpEnum() == Tomb.PositionEnum.POSITION_NONE_VALUE) {
                        position.setDecoration("w6");
                        position.setpEnum(Tomb.PositionEnum.POSITION_DECORATION_VALUE);
                    }
                    if (position.geteType() == Tomb.EventEnum.EVENT_BUFF_VALUE && position.getFlag() == 1) {
                        this.buffEventMap.put(position.getKey(), position);
                    }

                    this.positionMap.put(position.getKey(), position);

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        this.floor = dbTombMaze.getFloor();

        iEventMap.put(Tomb.EventEnum.EVENT_BUFF_VALUE, new Buff());
        iEventMap.put(Tomb.EventEnum.EVENT_NPC_BATTLE_VALUE, new NpcBattle());
        iEventMap.put(Tomb.EventEnum.EVENT_ELITE_NPC_BATTLE_VALUE, new EliteNpcBattle());
        iEventMap.put(Tomb.EventEnum.EVENT_BOSS_BATTLE_VALUE, new BossBattle());
        iEventMap.put(Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE, new PvpBattle());
        iEventMap.put(Tomb.EventEnum.EVENT_RELIQUE_VALUE, new Relique());
        iEventMap.put(Tomb.EventEnum.EVENT_TRAP_VALUE, new Trap());
        iEventMap.put(Tomb.EventEnum.EVENT_CHOOSE_VALUE, new Choose());
        iEventMap.put(Tomb.EventEnum.EVENT_ENTER_VALUE, new GoDownStairs());
        iEventMap.put(Tomb.EventEnum.EVENT_NONE_VALUE, new EmptyEvent());


        this.initPathAreaSet();
        this.pathMerge();
    }


    public DbTombMaze getDbTombMaze() {
        return dbTombMaze;
    }

    public void setDbTombMaze(DbTombMaze dbTombMaze) {
        this.dbTombMaze = dbTombMaze;
    }

    public int getFloor() {
        return floor;
    }

    public void setFloor(int floor) {
        this.floor = floor;
    }


    public Tomb.FieldTemp.Builder getFieldTemp(DbTombUser dbTombUser, long timestamp, Tomb.PositionTemp start, Tomb.PositionTemp end) {
        Tomb.FieldTemp.Builder builder = Tomb.FieldTemp.newBuilder();
        int startRow = start.getRow();
        int startColumn = start.getColumn();
        int endRow = end.getRow();
        int endColumn = end.getColumn();

        int maxRow = this.dbTombMaze.getMaze().getMaxRow();
        int maxColumn = this.dbTombMaze.getMaze().getMaxColumn();

        if (startRow >= maxRow) {
            startRow = maxRow - 1;
        }
        if (startColumn >= maxColumn) {
            startColumn = maxColumn - 1;
        }
        if (endRow >= maxRow) {
            endRow = maxRow - 1;
        }
        if (endColumn >= maxColumn) {
            endColumn = maxColumn - 1;
        }
        long now = Instant.now().toEpochMilli();
        for (int i = startRow; i <= endRow; i++) {
            for (int j = startColumn; j <= endColumn; j++) {
                try {
                    Position position = this.getPosition(i, j);
                    if (position == null) {
                        if (timestamp == 0) {
                            Tomb.PositionTemp.Builder p = Tomb.PositionTemp.newBuilder();
                            p.setRow(i);
                            p.setColumn(j);
                            p.setEnum(Tomb.PositionEnum.POSITION_ROAD_VALUE);
                            p.setEventEnum(Tomb.EventEnum.EVENT_NONE_VALUE);
                            builder.addField(p);
                        }
                        continue;
                    }
                    Tomb.PositionTemp.Builder p = Tomb.PositionTemp.newBuilder();
                    p.setRow(i);
                    p.setColumn(j);
                    p.setIsFlag(position.getFlag() == 1);
                    p.setDecoration(position.getDecoration());
                    p.setIsOver(true);
                    if (position.getpRelation().length() > 0) {
                        Position realPosition = this.getRealPosition(position.getRow(), position.getColumn());
                        if (realPosition != null) {
                            position = realPosition;
                        }
                    }
                    if (position.getTimestamp() < timestamp) {
                        continue;
                    }
                    p.setEnum(position.getpEnum());
                    p.setEventEnum(position.geteType());
                    if (position.getKillUserId() > 0) {
                        DbTombUser dbTombUser1 = this.getActivity().getDbData().getDbTombUser(position.getKillUserId());
                        if (dbTombUser1 != null) {
                            p.setFinishUser(dbTombUser1.toEventUserInfoBuilder());
                        }
                    }
                    IEvent iEvent = this.getEvent(position);
                    iEvent.display(dbTombUser, this, position, p);
                    builder.addField(p);
                } catch (Exception e) {
                    logger.error("getFieldTemp error" + e.getMessage());
                }
            }
        }
        builder.setTimestamp(now);
        return builder;
    }

    public IEvent getEvent(Position position) {
        if (position.hasEvent()) {
            return this.iEventMap.get(position.geteType());
        }
        return this.iEventMap.get(0);
    }

    public IEvent getEvent(int type) {
        return this.iEventMap.get(type);
    }

    public boolean canStand(DbTombUser dbTombUser, Position position) {
        IEvent iEvent = this.getEvent(position);
        return iEvent.canStand(dbTombUser, this, position);
    }

    public boolean canThrough(DbTombUser dbTombUser, Position position) {
        IEvent iEvent = this.getEvent(position);
        return iEvent.canThrough(dbTombUser, this, position);
    }

    public boolean canExplore(DbTombUser dbTombUser, Position position) {
        IEvent iEvent = this.getEvent(position);
        return iEvent.canExplore(dbTombUser, this, position);
    }


    public List<Coordinate> exploreMove(DbTombUser dbTombUser, int x, int y) {
        Coordinate start = Coordinate.newInstance(dbTombUser.getX(), dbTombUser.getY());
        List<Coordinate> coordinateList = this.getStandPositionAroundCoordinate(start, x, y);
        List<Coordinate> resultList = null;
        boolean multiGrip = coordinateList.size() > 1;
        for (Coordinate coordinate : coordinateList) {
            //如果是9格事件，例BUFF，先判定边上有没有空格可以站
            if (multiGrip) {
                boolean canStand = false;
                for (int i = -1; i <= 1; i++) {
                    for (int j = -1; j <= 1; j++) {
                        if (Math.abs(i) == Math.abs(j)) {
                            continue;
                        }
                        int _x = coordinate.getX() + i;
                        int _y = coordinate.getY() + j;
                        Position realPosition = this.getRealPosition(_x, _y);
                        if (realPosition == null || this.canStand(dbTombUser, realPosition)) {
                            canStand = true;
                            break;
                        }
                    }
                    if (canStand) {
                        break;
                    }
                }
                if (!canStand) {
                    continue;
                }
            }
            if (start.equals(coordinate)) {
                resultList = new ArrayList<>();
                resultList.add(coordinate);
                return resultList;
            }
            AStarMaze aStarMaze = new AStarMaze(this, dbTombUser, this.dbTombMaze.getMaze().getMaxRow(), this.dbTombMaze.getMaze().getMaxColumn(), start, coordinate);
            resultList = aStarMaze.star();
            if (resultList != null) {
                break;
            }
        }
        if (resultList == null) {
            return null;
        }
        return resultList;
    }

    public void eventTakeCare(DbTombUser dbTombUser, Tomb.TombEventTakeCareReq req, Tomb.TombEventExploreResp.Builder builder) {
        Coordinate start = Coordinate.newInstance(dbTombUser.getX(), dbTombUser.getY());
        Coordinate coordinate = Coordinate.newInstance(req.getRow(), req.getColumn());
        Tomb.CoordinateTemp.Builder coordinateTempBuilder = Tomb.CoordinateTemp.newBuilder();
        coordinateTempBuilder.setFloor(this.getFloor());
        coordinateTempBuilder.setRow(start.getX());
        coordinateTempBuilder.setColumn(start.getY());
        builder.setStand(coordinateTempBuilder);


        Tomb.TombEventExploreReq.Builder explore = Tomb.TombEventExploreReq.newBuilder();
        explore.setAction(2);
        explore.setRow(coordinate.getX());
        explore.setColumn(coordinate.getY());
        this.eventExplore(dbTombUser, explore.build(), builder);
        if (builder.getRet() > 0) {
            return;
        }

        if (builder.getAction() != 2) {
            return;
        }
        Tomb.PositionTemp position = builder.getPosition();
        Tomb.TombEventTouchReq.Builder touch = Tomb.TombEventTouchReq.newBuilder();
        Tomb.TombEventTouchResp.Builder touchResp = Tomb.TombEventTouchResp.newBuilder();
        try {
            if ((position.getEventEnum() == Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE && req.getEventTypeList().contains(Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE)) ||
                    position.getEventEnum() == Tomb.EventEnum.EVENT_NPC_BATTLE_VALUE && req.getEventTypeList().contains(Tomb.EventEnum.EVENT_NPC_BATTLE_VALUE)) {
                if (position.getHp() == 0) {
                    return;
                }
                touch.setTargetPosition(position);
                this.eventTouch(dbTombUser, touch.build(), touchResp);
                builder.setAfterAuto(touchResp.getTargetPosition());
            } else if (position.getEventEnum() == Tomb.EventEnum.EVENT_CHOOSE_VALUE && req.getEventTypeList().contains(Tomb.EventEnum.EVENT_CHOOSE_VALUE)) {
                touch.setTargetPosition(position);
                ActivityTombEvent activityTombEvent = this.getActivity().getConfig().getEvent(position.getEventConfig().getEventId());
                if (req.getChoseEventFinishList().contains(activityTombEvent.getId())) {
                    touch.setRelationId(0);
                    List<Integer> param4 = activityTombEvent.getParam4();
                    for (int i = 0; i < param4.size(); i++) {
                        if (param4.get(i) == 1) {
                            touch.setRelationId(i);
                        }
                    }
                } else {
                    return;
                }
                this.eventTouch(dbTombUser, touch.build(), touchResp);
                builder.setAfterAuto(touchResp.getTargetPosition());
            }
        } finally {
            Property property = new Property();
            Property property1 = PropertyHelper.parseStringToProperty(builder.getRewards());
            if (property1 != null) {
                property.addProperty(property1);
            }
            Property property2 = PropertyHelper.parseStringToProperty(touchResp.getRewards());
            if (property2 != null) {
                property.addProperty(property2);
            }

            builder.addAllRewardList(touchResp.getRewardListList());

            builder.setRewards(PropertyHelper.parsePropertyToString(property));
            builder.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
            builder.setEnergyLastTime(dbTombUser.getEnergyUpdateTime());
            builder.setPersonalScore(dbTombUser.getScore());
            builder.setUnionScore(dbTombUser.getUnionScore());
        }
    }


    public void eventExplore(DbTombUser dbTombUser, Tomb.TombEventExploreReq req, Tomb.TombEventExploreResp.Builder builder) {
        int x = req.getRow();
        int y = req.getColumn();
        logger.info("eventExplore : user:{},{}  req :{},{}", dbTombUser.getX(), dbTombUser.getY(), x , y);
        int flag = 0;
        int eventType = 0;
        if (dbTombUser.getLockEvent().length() > 0) {
            Position position = new Position(dbTombUser.getLockEvent());
            if (req.getRow() != position.getRow() || req.getColumn() != position.getColumn()) {
                builder.setRet(GameErrorCode.E_TOMB_EVENT_NOT_HANDLE);
                return;
            }
        }

        Coordinate startCoordinate = Coordinate.newInstance(dbTombUser.getX(), dbTombUser.getY());

        int lockIndex = 0;
        Position position = this.getRealPosition(x, y);
        if (position == null) {
            List<Position> tianshuList = new ArrayList<>(getBuffEventMap().values());
            for (Position tP : tianshuList) {
                int row = tP.getRow() - x;
                int column = tP.getColumn() - y;
                if (0<=row && row <=2 && column >=0 && column <=2 ) {
                    position = tP;
                    break;
                }
            }
        }
        if (position != null) {
            lockIndex = position.getLockIndex();
            x = position.getRow();
            y = position.getColumn();
            flag = position.getFlag();
            eventType = position.geteType();
        }
        Lock positionLock = this.getPositionLock(lockIndex);
        positionLock.lock();

        try {
            if (position != null && !position.canClick()) {
                builder.setRet(GameErrorCode.E_TOMB_CAN_NOT_MOVE);
                return;
            }
            List<Coordinate> canStandList = new ArrayList<>();
            if (position != null && !this.canStand(dbTombUser, position)) {
                Map<String, Coordinate> canStandPositionAroundCoordinate = this.getCanStandPositionAroundCoordinate(dbTombUser, x, y);
                canStandList.addAll(canStandPositionAroundCoordinate.values());
            } else {
                Coordinate coordinate = Coordinate.newInstance(req.getRow(), req.getColumn());
                canStandList.add(coordinate);
            }
            if (canStandList.size() == 0) {
                builder.setRet(GameErrorCode.E_TOMB_CAN_NOT_MOVE);
                return;
            }
            canStandList.sort(Comparator.comparing(Coordinate::getDistance));

            Coordinate standCoordinate = null;

            for (Coordinate coordinate : canStandList) {
                if (this.inSamePathArea(dbTombUser, coordinate)) {
                    standCoordinate = coordinate;
                    break;
                }
            }

            if (standCoordinate == null) {
                builder.setRet(GameErrorCode.E_TOMB_CAN_NOT_MOVE);
                return;
            }

            //客户端传2过来，如果该格子不能开，则返回
            if (req.getAction() == 2) {
                if (position == null || !this.canExplore(dbTombUser, position)) {
                    builder.setPersonalScore(dbTombUser.getScore());
                    builder.setUnionScore(dbTombUser.getUnionScore());
                    builder.setAction(0);
                    return;
                }
            }

            Tomb.PositionTemp.Builder positionTempBuilder = Tomb.PositionTemp.newBuilder();
            List<Coordinate> coordinateList = null;
            int distance = this.getToEndDistance(dbTombUser, standCoordinate);
            int teleportDecide = this.getActivity().getConfig().getConfig().getTOMB_TELEPORT_DECIDE();
            //如果超过了配置的距离，则直接飞走，不用寻路
            if (distance > teleportDecide) {
                Tomb.CoordinateTemp.Builder temp = Tomb.CoordinateTemp.newBuilder();
                temp.setFloor(this.getFloor());
                temp.setRow(standCoordinate.getX());
                temp.setColumn(standCoordinate.getY());
                for (int i = 0; i < teleportDecide + 1; i++) {
                    builder.addPath(temp);
                }
                builder.setStand(temp);
            } else {
                coordinateList = this.exploreMove(dbTombUser, req.getRow(), req.getColumn());
                if (coordinateList == null) {
                    Tomb.CoordinateTemp.Builder temp = Tomb.CoordinateTemp.newBuilder();
                    temp.setFloor(this.getFloor());
                    temp.setRow(standCoordinate.getX());
                    temp.setColumn(standCoordinate.getY());
                    for (int i = 0; i < teleportDecide + 1; i++) {
                        builder.addPath(temp);
                    }
                    builder.setStand(temp);
                } else {
                    boolean end = false;
                    List<Coordinate> resultList = new ArrayList<>();
                    for (Coordinate coordinate : coordinateList) {
                        Position position1 = this.getRealPosition(coordinate.getX(), coordinate.getY());
                        if (!end) {
                            if (position1 != null && !this.canStand(dbTombUser, position1)) {
                                continue;
                            }
                        }
                        end = true;
                        resultList.add(coordinate);
                    }

                    for (int i = resultList.size() - 1; i >= 0; i--) {
                        Coordinate coordinate1 = resultList.get(i);
                        Tomb.CoordinateTemp.Builder temp = Tomb.CoordinateTemp.newBuilder();
                        temp.setFloor(this.getFloor());
                        temp.setRow(coordinate1.getX());
                        temp.setColumn(coordinate1.getY());
                        builder.addPath(temp);
                        builder.setStand(temp);
                    }
                }

            }


            Tomb.CoordinateTemp.Builder from = Tomb.CoordinateTemp.newBuilder();
            from.setFloor(this.floor);
            from.setRow(dbTombUser.getX());
            from.setColumn(dbTombUser.getY());

            positionTempBuilder.setRow(x);
            positionTempBuilder.setColumn(y);
            positionTempBuilder.setIsFlag(flag == 1);

            //这里判断是不是存在属于自已商会的PVP事件
            boolean isUnionPvpEvent = false;
            if (position != null && position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_VALUE && position.geteType() == Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE) {
                DbTombPosition dbTombPosition = this.getDbTombPosition(position.getKey());
                if (dbTombPosition != null && dbTombPosition.getDone() == 0) {
                    boolean isContain = dbTombPosition.containUnionDig(dbTombUser.getUserInfo().getUnionUid());
                    if (isContain) {
                        DbTombUser pvpDbTombUser = this.getActivity().getDbData().getDbTombUser(dbTombPosition.getPvpUserId());
                        if (pvpDbTombUser != null) {
                            if (pvpDbTombUser.isAlive()) {
                                isUnionPvpEvent = true;
                            }
                        }
                    }
                }
            }

            IEvent iEvent = null;
            if (position != null) {
                iEvent = this.getEvent(position);
            } else {
                iEvent = this.getEvent(0);
            }

            if (position != null && (position.geteType() == Tomb.EventEnum.EVENT_BUFF_VALUE || isUnionPvpEvent)) {
                builder.setAction(3);
                iEvent.detail(this, dbTombUser, position, positionTempBuilder, builder);
            } else {
                if (position == null || iEvent.canStand(dbTombUser, this, position)) {
                    builder.setAction(1);
                    positionTempBuilder.setEnum(position == null ? Tomb.PositionEnum.POSITION_ROAD_VALUE : position.getpEnum());
                    positionTempBuilder.setEventEnum(eventType);
                    positionTempBuilder.setIsOver(true);
                    if (eventType == Tomb.EventEnum.EVENT_ENTER_VALUE) {
                        builder.setAction(3);
                    }
                } else if (iEvent.canExplore(dbTombUser, this, position)) {
                    builder.setAction(2);
                    this.exploreDig(dbTombUser, position, positionTempBuilder, builder);
                } else {
                    builder.setAction(3);
                    iEvent.detail(this, dbTombUser, position, positionTempBuilder, builder);
                }
            }
            builder.setPersonalScore(dbTombUser.getScore());
            builder.setUnionScore(dbTombUser.getUnionScore());
            if (builder.getStand().getRow() > 0 || builder.getStand().getColumn() > 0) {
                dbTombUser.setX(builder.getStand().getRow());
                dbTombUser.setY(builder.getStand().getColumn());
            }
            Tomb.AllyInfo.Builder allyInfoBuilder = dbTombUser.toAllyInfoBuilder();
            if (allyInfoBuilder.getIsInTrap()) {
                DbTombPosition dbTombPosition = this.activity.getDbData().getDbTombPosition(dbTombUser.getGroupId(), this.getFloor(), dbTombUser.getPositionKey());
                if (dbTombPosition != null) {
                    allyInfoBuilder.setOverTimestamp(dbTombPosition.getOverTime());
                } else {
                    allyInfoBuilder.setIsInTrap(false);
                    dbTombUser.setStatus(0);
                    dbTombUser.refreshUpdateTime();
                }
            }
            this.activity.moveNotify(this.floor, from.build(), dbTombUser, builder.getPathList(), allyInfoBuilder);
            dbTombUser.refreshUpdateTime();
            builder.setPosition(positionTempBuilder);
            builder.setAssistTimes(dbTombUser.getAssistTimes());

            LocalDateTime now = LocalDateTime.now();
            //发到游戏服写日志
            Tomb.TombLogCrossToGameReq.Builder logBuilder = Tomb.TombLogCrossToGameReq.newBuilder();
            logBuilder.setLEnum(Tomb.GameTombLogEnum.MOVE);
            logBuilder.setUserId(dbTombUser.getUserId());
            logBuilder.setActivityId(this.getActivityId());
            logBuilder.setUnionUid(dbTombUser.getUserInfo().getUnionUid());
            logBuilder.setFloor(dbTombUser.getFloor());
            logBuilder.setX(dbTombUser.getX());
            logBuilder.setY(dbTombUser.getY());
            logBuilder.setHp(dbTombUser.getHp());
            logBuilder.setTimestamp(now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
            Tomb.TombLogMove.Builder move = Tomb.TombLogMove.newBuilder();
            if (builder.getPosition() != null) {
                if (builder.getPosition().getEventConfig() != null) {
                    move.setEventId(builder.getPosition().getEventConfig().getEventId());
                }
            }
            logBuilder.setMove(move);
            this.getActivity().sendLogToGame(dbTombUser, logBuilder);

            this.addPathToAreaSet(startCoordinate, x, y);

        } finally {
            positionLock.unlock();
        }


    }


    public synchronized void exploreDig(DbTombUser dbTombUser, Position position, Tomb.PositionTemp.Builder positionTempBuilder, Tomb.TombEventExploreResp.Builder builder) {

        if (!this.costEnergy(dbTombUser, 0, 0)) {
            builder.setRet(GameErrorCode.E_TOMB_USER_NOT_ENOUGH_ENERGY);
            return;
        }
        boolean hasBigEvent = false;
        Position position1 = this.fullBigEvent(position);
        if (position1 != null) {
            hasBigEvent = true;
        }
        long pvpUserId = 0;
        boolean finalBoss = this.activity.isFinalBoss(dbTombUser.getGroupId(), this.floor);
        //获取随机事件
        ActivityTombEvent activityTombEvent = this.randomActivityTombEvent(hasBigEvent, finalBoss, this.dbTombMaze);
        if (activityTombEvent.isPvp()) {
            this.dbTombMaze.addExplored(activityTombEvent.getId());
            pvpUserId = this.getPvpUserId(dbTombUser);
            if (pvpUserId == 0) {
                activityTombEvent = this.randomNpcBattle(this.dbTombMaze);
                if (activityTombEvent == null) {
                    builder.setRet(GameErrorCode.E_ERROR_DATA);
                    return;
                }
            }
        } else {
            this.dbTombMaze.addExplored(activityTombEvent.getId());
        }
        if (activityTombEvent.isBigEvent()) {
            if (position1 != null) {
                position = position1;
            }
            this.getDbTombMaze().increaseBrakeBigGripNum();
            this.getDbTombMaze().increaseExploredBigEventNum();
            position.setpEnum(Tomb.PositionEnum.POSITION_EVENT_VALUE);
            position.seteType(activityTombEvent.getEventType());
        } else {
            if (position1 != null) {
                this.getDbTombMaze().increaseBrakeBigGripNum();
                position1.setFlag(0);
                this.updateGrip(position1);
            }
            this.getDbTombMaze().increaseExploredNormalEventNum();
            position.setpRelation("");
            position.setpEnum(Tomb.PositionEnum.POSITION_EVENT_VALUE);
            position.seteType(activityTombEvent.getEventType());
        }

        DbTombPosition dbTombPosition = this.getActivity().getDbData().initDbTombPosition(dbTombUser.getGroupId(), this.floor, position);
        dbTombPosition.setGroupId(dbTombUser.getGroupId());
        dbTombPosition.setEventId(activityTombEvent.getId());
        if (activityTombEvent.isPvp()) {
            dbTombPosition.setPvpUserId(pvpUserId);
        }
        IEvent iEvent = this.getEvent(position);
        dbTombPosition.addUnionDigUser(dbTombUser.getUserInfo().getUnionUid(), dbTombUser.getUserId());
        iEvent.explore(this, dbTombUser, dbTombPosition, position, activityTombEvent, positionTempBuilder, builder);
        //检查玩偶是否到期
        TombServiceMgr.checkDollOverTime(this.getActivityId(), dbTombUser);
        this.updateGrip(position);

        this.addExploredNum(dbTombUser, 1);

        positionTempBuilder.setDigUser(dbTombUser.toEventUserInfoBuilder());
        positionTempBuilder.setEventConfig(activityTombEvent.getEventConfigBuilder());
        positionTempBuilder.setIsFlag(position.getFlag() == 1);
        positionTempBuilder.setRow(position.getRow());
        positionTempBuilder.setColumn(position.getColumn());
        dbTombPosition.refreshUpdateTime();

        builder.setPersonalScore(dbTombUser.getScore());
        builder.setUnionScore(dbTombUser.getUnionScore());

        this.activity.getActivityUnion(dbTombUser.getUserInfo().getUnionUid()).addDbTombPosition(dbTombPosition);
        dbTombUser.refreshUpdateTime();
        builder.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
        builder.setEnergyLastTime(dbTombUser.getEnergyUpdateTime());
        builder.setPosition(positionTempBuilder);
        builder.setPersonalScore(dbTombUser.getScore());
        builder.setUnionScore(dbTombUser.getUnionScore());
        this.dbTombMaze.refreshUpdateTime();
    }

    public Property addProperty(Property property, DbTombUser dbTombUser) {
        if (property == null) {
            return null;
        }
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            if (entry.getKey() == this.getConfig().getConfig().getTOMB_SCORE_ITEM_ID()) {
                long i = entry.getValue().intValue();
                int dollScoreBuffPercentage = this.activity.getDollScoreBuffPercentage(dbTombUser);
                if (dollScoreBuffPercentage > 0) {
                    i = (long) ((double) i * (1 + (double) dollScoreBuffPercentage / 1000));
                }
                dbTombUser.addScore(i);
                property.setGood(entry.getKey(), BigInteger.valueOf(i));


                //发到游戏服写日志
                Tomb.TombLogCrossToGameReq.Builder logBuilder = Tomb.TombLogCrossToGameReq.newBuilder();
                logBuilder.setLEnum(Tomb.GameTombLogEnum.SCORE);
                logBuilder.setUserId(dbTombUser.getUserId());
                logBuilder.setActivityId(this.getActivityId());
                logBuilder.setUnionUid(dbTombUser.getUserInfo().getUnionUid());
                logBuilder.setFloor(dbTombUser.getFloor());
                logBuilder.setX(dbTombUser.getX());
                logBuilder.setY(dbTombUser.getY());
                logBuilder.setHp(dbTombUser.getHp());
                logBuilder.setTimestamp(System.currentTimeMillis());
                Tomb.TombLogScore.Builder score = Tomb.TombLogScore.newBuilder();
                score.setType(1);
                score.setScoreChange(i);
                score.setScore(dbTombUser.getScore());
                logBuilder.setScore(score);

                this.getActivity().sendLogToGame(dbTombUser, logBuilder);

            } else if (entry.getKey() == this.getConfig().getConfig().getTOMB_GUILD_SCORE_ITEM_ID()) {
                dbTombUser.addUnionScore(entry.getValue().intValue());

                //发到游戏服写日志
                Tomb.TombLogCrossToGameReq.Builder logBuilder = Tomb.TombLogCrossToGameReq.newBuilder();
                logBuilder.setLEnum(Tomb.GameTombLogEnum.SCORE);
                logBuilder.setUserId(dbTombUser.getUserId());
                logBuilder.setActivityId(this.getActivityId());
                logBuilder.setUnionUid(dbTombUser.getUserInfo().getUnionUid());
                logBuilder.setFloor(dbTombUser.getFloor());
                logBuilder.setX(dbTombUser.getX());
                logBuilder.setY(dbTombUser.getY());
                logBuilder.setHp(dbTombUser.getHp());
                logBuilder.setTimestamp(System.currentTimeMillis());
                Tomb.TombLogScore.Builder score = Tomb.TombLogScore.newBuilder();
                score.setType(2);
                score.setScoreChange(entry.getValue().intValue());
                score.setScore(dbTombUser.getUnionScore());
                logBuilder.setScore(score);

                this.getActivity().sendLogToGame(dbTombUser, logBuilder);


            }
        }
        return property;
    }

    public Property addProperty(String s, DbTombUser dbTombUser) {
        if (s == null) {
            return null;
        }
        Property property = PropertyHelper.parseStringToProperty(s);
        return this.addProperty(property, dbTombUser);
    }


    public void updateGrip(Position position) {
        position.refreshTimestamp();
        this.dbTombMaze.getMaze().updatePosition(position);
        this.dbTombMaze.refreshUpdateTime();
    }


    public void eventInfo(DbTombUser dbTombUser, Tomb.TombEventInfoReq req, Tomb.TombEventInfoResp.Builder builder) {
        Tomb.PositionTemp positionTemp = req.getTargetPosition();
        if (req.getHeartbeat() > 0) {
            return;
        }
        Position position = this.getRealPosition(positionTemp.getRow(), positionTemp.getColumn());
        if (position == null) {
            builder.setRet(GameErrorCode.E_TOMB_EVENT_DONE);
            return;
        }


        Tomb.PositionTemp.Builder positionTempBuilder = Tomb.PositionTemp.newBuilder();

        positionTempBuilder.setRow(position.getRow());
        positionTempBuilder.setColumn(position.getColumn());
        positionTempBuilder.setEnum(position.getpEnum());
        positionTempBuilder.setEventEnum(position.geteType());
        positionTempBuilder.setIsFlag(position.getFlag() == 1);

        if (position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE) {
            if (position.geteType() != Tomb.EventEnum.EVENT_TRAP_VALUE) {
                dbTombUser.refreshUpdateTime();
                return;
            }
        }

        if (position.geteType() == Tomb.EventEnum.EVENT_BUFF_VALUE) {
            IEvent iEvent = this.getEvent(position);
            ;
            ActivityTombEvent activityTombEvent = this.getConfig().getEvents(1).get(0);
            iEvent.info(this, dbTombUser, null, position, activityTombEvent, positionTempBuilder, builder);
            builder.setTargetPosition(positionTempBuilder);

            return;
        }

        DbTombPosition dbTombPosition = this.getActivity().getDbData().getDbTombPosition(dbTombUser.getGroupId(), this.floor, position.getKey());
        if (dbTombPosition == null) {
            builder.setRet(GameErrorCode.E_ERROR_DATA);
            return;
        }

        if (dbTombPosition.getDone() == 1) {
            positionTempBuilder.setEnum(Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE);
            builder.setTargetPosition(positionTempBuilder);
            return;
        }

        ActivityTombEvent activityTombEvent = this.getConfig().getEvent(dbTombPosition.getEventId());

        if (position.getpEnum() != Tomb.PositionEnum.POSITION_EVENT_VALUE) {
            if (position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE) {
                if (position.geteType() == Tomb.EventEnum.EVENT_CHOOSE_VALUE || position.geteType() == Tomb.EventEnum.EVENT_TRAP_VALUE) {
                    IEvent iEvent = this.getEvent(position);
                    iEvent.info(this, dbTombUser, dbTombPosition, position, activityTombEvent, positionTempBuilder, builder);
                    builder.setTargetPosition(positionTempBuilder);
                    return;
                }
                builder.setRet(GameErrorCode.E_ERROR_DATA);
                return;
            }
            return;
        }

        dbTombPosition.getLock().lock();
        try {
            if (req.getSubType() == 1) {
                ArrayList<PositionInfo> positionInfos = new ArrayList<>(dbTombPosition.getEventInfoMap().values());
                positionInfos.sort(Comparator.comparing(PositionInfo::getAttack).reversed());

                for (PositionInfo positionInfo : positionInfos) {
                    Tomb.TombEventSubInfoTemp.Builder subInfo = Tomb.TombEventSubInfoTemp.newBuilder();
                    subInfo.setId(positionInfo.getUserId());
                    subInfo.setValue(positionInfo.getAttack());
                    DbTombUser dbTombUser1 = this.getActivity().getDbData().getDbTombUser(subInfo.getId());
                    if (dbTombUser1 != null) {
                        subInfo.setName(dbTombUser1.getUserInfo().getNickName());
                    } else {
                        subInfo.setName("无名");
                    }
                    builder.addSubInfoList(subInfo);
                }
            }
            IEvent iEvent = this.getEvent(position);
            iEvent.info(this, dbTombUser, dbTombPosition, position, activityTombEvent, positionTempBuilder, builder);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            dbTombPosition.getLock().unlock();
        }


        dbTombUser.refreshUpdateTime();
        builder.setTargetPosition(positionTempBuilder);
    }

    public void eventTouch(DbTombUser dbTombUser, Tomb.TombEventTouchReq req, Tomb.TombEventTouchResp.Builder builder) {
        Tomb.PositionTemp positionTemp = req.getTargetPosition();

        Position position = this.getRealPosition(positionTemp.getRow(), positionTemp.getColumn());
        if (position == null) {
            builder.setRet(GameErrorCode.E_TOMB_EVENT_DONE);
            return;
        }
        Coordinate startCoordinate = Coordinate.newInstance(dbTombUser.getX(), dbTombUser.getY());

        Tomb.PositionTemp.Builder positionTempBuilder = Tomb.PositionTemp.newBuilder();
        positionTempBuilder.setRow(position.getRow());
        positionTempBuilder.setColumn(position.getColumn());
        builder.setPersonalScore(dbTombUser.getScore());
        builder.setUnionScore(dbTombUser.getUnionScore());

        positionTempBuilder.setIsFlag(position.getFlag() == 1);
        positionTempBuilder.setEnum(position.getpEnum());
        positionTempBuilder.setEventEnum(position.geteType());
        builder.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
        builder.setEnergyLastTime(dbTombUser.getEnergyUpdateTime());
        builder.setTargetPosition(positionTempBuilder);


        if (position.geteType() == Tomb.EventEnum.EVENT_BUFF_VALUE) {
            ActivityTombEvent activityTombEvent = this.getConfig().getEvents(1).get(0);
            IEvent iEvent = this.iEventMap.get(position.geteType());
            iEvent.touch(this, dbTombUser, null, position, activityTombEvent, positionTempBuilder, builder, req);
            builder.setPersonalScore(dbTombUser.getScore());
            builder.setUnionScore(dbTombUser.getUnionScore());

            positionTempBuilder.setIsFlag(position.getFlag() == 1);
            positionTempBuilder.setEnum(position.getpEnum());
            positionTempBuilder.setEventEnum(position.geteType());
            builder.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
            builder.setEnergyLastTime(dbTombUser.getEnergyUpdateTime());
            builder.setTargetPosition(positionTempBuilder);
            return;
        }

        if (position.getKillUserId() > 0) {
            DbTombUser dbTombUser1 = this.getActivity().getDbData().getDbTombUser(position.getKillUserId());
            if (dbTombUser1 != null) {
                positionTempBuilder.setFinishUser(dbTombUser1.toEventUserInfoBuilder());
            }
        }

        DbTombPosition dbTombPosition = this.getActivity().getDbData().getDbTombPosition(dbTombUser.getGroupId(), this.floor, position.getKey());
        if (dbTombPosition == null) {
            builder.setRet(GameErrorCode.E_TOMB_EVENT_DONE);
            return;
        }
        ActivityTombEvent activityTombEvent = this.getConfig().getEvent(dbTombPosition.getEventId());
        positionTempBuilder.setEventConfig(activityTombEvent.getEventConfigBuilder());


        dbTombPosition.getLock().lock();

        try {
            IEvent iEvent = this.iEventMap.get(position.geteType());
            iEvent.touch(this, dbTombUser, dbTombPosition, position, activityTombEvent, positionTempBuilder, builder, req);
            dbTombPosition.refreshUpdateTime();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            dbTombPosition.getLock().unlock();
        }


        builder.setPersonalScore(dbTombUser.getScore());
        builder.setUnionScore(dbTombUser.getUnionScore());
        builder.setRewardScore(dbTombUser.getRewardScore());

        positionTempBuilder.setIsFlag(position.getFlag() == 1);
        positionTempBuilder.setEnum(position.getpEnum());
        positionTempBuilder.setEventEnum(position.geteType());
        dbTombUser.refreshUpdateTime();
        builder.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
        builder.setEnergyLastTime(dbTombUser.getEnergyUpdateTime());
        builder.setTargetPosition(positionTempBuilder);
        builder.setAssistTimes(dbTombUser.getAssistTimes());
        this.addPathToAreaSet(startCoordinate, position.getRow(), position.getColumn());
    }

    public String getPositionKey(int row, int column) {
        return String.format("%d_%d", row, column);
    }


    public Position getRealPosition(int row, int column) {
        String positionKey = this.getPositionKey(row, column);
        return this.getRealPosition(positionKey);
    }

    public Position getRealPosition(String positionKey) {
        Position position = this.getPosition(positionKey);
        if (position != null && position.getpRelation().length() > 0) {
            Position _position = this.getPosition(position.getpRelation());
            if (_position != null && _position.getFlag() == 1) {
                if (_position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_VALUE ||
                        _position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE) {
                    position = _position;
                }
            }
        }
        return position;
    }

    /**
     * 如果获取的数据为空，说明这个位置，是路，或者是已经完成的事件
     *
     * @param row
     * @param column
     * @return
     */
    public Position getPosition(int row, int column) {
        String s = String.format("%d_%d", row, column);
        return this.getPosition(s);
    }

    /**
     * 如果获取的数据为空，说明这个位置，是路，或者是已经完成的事件
     *
     * @param s
     * @return
     */
    public Position getPosition(String s) {
        Position position = this.positionMap.get(s);
        return position;
    }

    @FunctionalInterface
    interface DigHandler {
        void handle();
    }

    @FunctionalInterface
    interface EventInfoHandler {
        void handle();
    }

    @FunctionalInterface
    interface EventTouchHandler {
        void handle();
    }


    public void eventBattleSyncPush(DbTombUser dbTombUser, long damage, long currentHp, String key, boolean goDownstairs) {
        Tomb.TombEventBattleSyncPush.Builder builder = Tomb.TombEventBattleSyncPush.newBuilder();
        builder.setId(dbTombUser.getUserId());
        builder.setDamage(damage);
        builder.setCurrentHp(currentHp);
        builder.setEventUserInfo(dbTombUser.toEventUserInfoBuilder());
        builder.setGoDownstairs(goDownstairs);
        Map<Long, Tomb.TombEventBattleSyncPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();
        List<HeartbeatInfo> eventList = this.activity.getHeartbeat().getEventList(key);
        for (HeartbeatInfo value : eventList) {
            if (value.getUserId() == dbTombUser.getUserId()) {
                continue;
            }
            if (!toGameReqMap.containsKey(value.getServerId())) {
                toGameReqMap.put(value.getServerId(), Tomb.TombEventBattleSyncPushCrossToGameReq.newBuilder().setResp(builder));
            }
            toGameReqMap.get(value.getServerId()).addUserIdList(value.getUserId());

        }
        toGameReqMap.forEach((serverId, _req) -> {
            MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_EVENT_BATTLE_SYNC_PUSH, this.activity.getActivityInfo().getActivityId(), 0, _req, null);
        });
    }


    public void eventEliteNpcInfoSyncPush(Tomb.TombEliteNpcInfoPush.Builder builder, DbTombUser dbTombUser, boolean allFloor) {
        Map<Long, Tomb.TombEliteNpcInfoPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();
        List<HeartbeatInfo> eventList = this.activity.getHeartbeat().getList(dbTombUser.getGroupId());
        for (HeartbeatInfo value : eventList) {
            if (builder.getScope() == 2) {
                if (!value.getUnionUid().equals(dbTombUser.getUserInfo().getUnionUid())) {
                    continue;
                }
            }
            if (!allFloor) {
                if (value.getFloor() != dbTombUser.getFloor()) {
                    continue;
                }
            }
            if (!toGameReqMap.containsKey(value.getServerId())) {
                toGameReqMap.put(value.getServerId(), Tomb.TombEliteNpcInfoPushCrossToGameReq.newBuilder().setResp(builder));
            }
            toGameReqMap.get(value.getServerId()).addUserIdList(value.getUserId());

        }
        toGameReqMap.forEach((serverId, _req) -> {
            MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_ELITE_NPC_INFO_PUSH, this.activity.getActivityInfo().getActivityId(), 0, _req, null);
        });
    }

    public List<Tomb.TombEventUserInfoTemp> getEventUserInfoList(DbTombUser dbTombUser, String key) {
        List<Tomb.TombEventUserInfoTemp> list = new ArrayList<>();
        List<HeartbeatInfo> heartbeatInfoList = this.activity.getHeartbeat().getEventList(key);
        for (HeartbeatInfo heartbeatInfo : heartbeatInfoList) {
            if (dbTombUser.getUserId() == heartbeatInfo.getUserId()) {
                continue;
            }
            DbTombUser dbTombUser1 = this.activity.getDbData().getDbTombUser(heartbeatInfo.getUserId());
            if (dbTombUser1 == null) {
                continue;
            }
            list.add(dbTombUser1.toEventUserInfoBuilder().build());
        }
        return list;
    }


    private List<DbTombUser> randPVPList(DbTombUser dbTombUser) {
        List<DbTombUser> list = new ArrayList<>();
        return list;
    }

    public TombConfig getConfig() {
        return this.getActivity().getConfig();
    }

    public int getActivityId() {
        return this.activity.getActivityInfo().getActivityId();
    }

    public TombActivity getActivity() {
        return activity;
    }


    public Tomb.TombEliteNpcInfoPush.Builder getEliteNpcInfo(DbTombUser dbTombUser) {
        Tomb.TombEliteNpcInfoPush.Builder eliteNpcInfoPushBuilder = Tomb.TombEliteNpcInfoPush.newBuilder();
        ActivityTombEvent activityTombEvent = this.getConfig().getEvent(this.getDbTombMaze().getEliteEventId());
        DbActivityTombInfo dbActivityTombInfo = this.activity.getDbData().getDbActivityTombInfo(dbTombUser.getGroupId());
        eliteNpcInfoPushBuilder.setFinalBossKilled(dbActivityTombInfo.getIsBossDead() == 1);

        if (this.activity.isFinalBoss(dbTombUser.getGroupId(), this.getFloor())) {
            ActivityTombEvent boss = this.getConfig().getBoss(this.floor);
            activityTombEvent = boss;
        }
        eliteNpcInfoPushBuilder.setNpcId(activityTombEvent.getNpcId());
        if (StringUtil.isNullOrEmpty(this.getDbTombMaze().getEliteNpcEvent())) {
            return eliteNpcInfoPushBuilder;
        }
        DbTombPosition dbTombPosition = this.getActivity().getDbData().getDbTombPosition(dbTombUser.getGroupId(), this.floor, this.getDbTombMaze().getEliteNpcEvent());
        if (dbTombPosition == null) {
            return eliteNpcInfoPushBuilder;
        }
        DbTombUser dbTombUser1 = this.activity.getDbData().getDbTombUser(dbTombPosition.acquireDigUser());
        if (dbTombUser1 != null) {
            eliteNpcInfoPushBuilder.setDigUser(dbTombUser1.toEventUserInfoBuilder());
        }
        eliteNpcInfoPushBuilder.setHp(dbTombPosition.getCurrentHp());
        eliteNpcInfoPushBuilder.setMaxHp(dbTombPosition.getMaxHp());
        Tomb.CoordinateTemp.Builder coordinateTempBuilder = Tomb.CoordinateTemp.newBuilder();
        coordinateTempBuilder.setFloor(dbTombPosition.getFloor());
        coordinateTempBuilder.setRow(dbTombPosition.getX());
        coordinateTempBuilder.setColumn(dbTombPosition.getY());
        eliteNpcInfoPushBuilder.setCoordinate(coordinateTempBuilder);
        DbTombUser dbTombUser2 = this.activity.getDbData().getDbTombUser(dbTombPosition.getFinishUserId());
        if (dbTombUser2 != null) {
            eliteNpcInfoPushBuilder.setFinishUser(dbTombUser2.toEventUserInfoBuilder());
        }
        Map<String, DigUserInfo> digUnionUserMap = dbTombPosition.getDigUnionUserMap();
        for (Map.Entry<String, DigUserInfo> entry : digUnionUserMap.entrySet()) {
            eliteNpcInfoPushBuilder.addUnionUid(entry.getKey());
        }

        eliteNpcInfoPushBuilder.setCoordinate(Tomb.CoordinateTemp.newBuilder().setRow(dbTombPosition.getX()).setColumn(dbTombPosition.getY()).setFloor(dbTombPosition.getFloor()).build());
        return eliteNpcInfoPushBuilder;
    }

    public DbTombPosition getDbTombPosition(String key) {
        return this.activity.getDbData().getDbTombPosition(this.dbTombMaze.getGroupId(), this.floor, key);
    }

    public long getPvpUserId(DbTombUser dbTombUser) {
        List<DbTombUser> dbTombUserRanking = this.getActivity().getDbData().getDbTombUserRanking(dbTombUser.getGroupId());
        dbTombUserRanking.sort(Comparator.comparing(DbTombUser::getTotalAttack).reversed());
        List<ChoosePvpUserInfo> allList = new ArrayList<>();
        int selfRank = 0;
        int maxRank = 0;
        for (int i = 0; i < dbTombUserRanking.size(); i++) {
            DbTombUser dbTombUser1 = dbTombUserRanking.get(i);
            ChoosePvpUserInfo choosePvpUserInfo = ChoosePvpUserInfo.newInstance();
            choosePvpUserInfo.setDbTombUser(dbTombUser1);
            choosePvpUserInfo.setRank(i + 1);
            if (dbTombUser1.getUserId() == dbTombUser.getUserId()) {
                selfRank = choosePvpUserInfo.getRank();
            }
            if (choosePvpUserInfo.getRank() > maxRank) {
                maxRank = choosePvpUserInfo.getRank();
            }
            allList.add(choosePvpUserInfo);
        }

        List<ChoosePvpUserInfo> list = new ArrayList<>();
        for (ChoosePvpUserInfo choosePvpUserInfo : allList) {
            DbTombUser pvpUserInfoDbTombUser = choosePvpUserInfo.getDbTombUser();
            if (dbTombUser.getUserInfo().getUnionUid().equals(pvpUserInfoDbTombUser.getUserInfo().getUnionUid())) {
                continue;
            }
            if (pvpUserInfoDbTombUser.getUserId() == dbTombUser.getUserId()) {
                continue;
            }

            if (pvpUserInfoDbTombUser.getStatus() == 2) {
                continue;
            }

            if (dbTombUser.getFloor() != pvpUserInfoDbTombUser.getFloor()) {
                continue;
            }
            if (pvpUserInfoDbTombUser.getGuideMark() == 0) {
                continue;
            }

            if (pvpUserInfoDbTombUser.getCostEnergy() == 0) {
                continue;
            }

            if (pvpUserInfoDbTombUser.getPvpChoseNum() >= this.getConfig().getConfig().getTOMB_PVP_BEATEN_BASE_NUM()) {
                continue;
            }
            if (pvpUserInfoDbTombUser.getPvpUnionChooseMap().size() >= this.getConfig().getConfig().getTOMB_PVP_BEATEN_BASE_NUM()) {
                continue;
            }
            if (pvpUserInfoDbTombUser.getPvpUnionChooseMap().contains(dbTombUser.getUserInfo().getUnionUid())) {
                continue;
            }
            if (!pvpUserInfoDbTombUser.isAlive()) {
                continue;
            }
            list.add(choosePvpUserInfo);
        }

        if (list.size() == 0) {
            return 0;
        }

        if (list.size() == 1) {
            return list.get(0).getDbTombUser().getUserId();
        }

        int whileTimes = 0;

        int around = 1;
        List<ChoosePvpUserInfo> rankList = new ArrayList<>();
        do {
            if (whileTimes >= 1000) {
                break;
            }
            whileTimes++;
            int randAround = around * 10;
            for (ChoosePvpUserInfo choosePvpUserInfo : list) {
                if (Math.abs(choosePvpUserInfo.getRank() - selfRank) <= randAround) {
                    rankList.add(choosePvpUserInfo);
                }
            }
            if (rankList.size() > 0) {
                break;
            }
            around++;

        } while (around * 10 <= maxRank);


        if (rankList.size() == 0) {
            return 0;
        }

        if (rankList.size() == 1) {
            return rankList.get(0).getDbTombUser().getUserId();
        }


        List<ChoosePvpUserInfo> pvpUserInfos1 = new ArrayList<>();
        List<ChoosePvpUserInfo> pvpUserInfos2 = new ArrayList<>();
        List<ChoosePvpUserInfo> pvpUserInfos3 = new ArrayList<>();
        List<ChoosePvpUserInfo> pvpUserInfos4 = new ArrayList<>();


        for (ChoosePvpUserInfo choosePvpUserInfo : rankList) {
            if (dbTombUser.getUserInfo().getServerId() != choosePvpUserInfo.getDbTombUser().getUserInfo().getServerId() && choosePvpUserInfo.getDbTombUser().isFullHp()) {
                pvpUserInfos1.add(choosePvpUserInfo);
            }
            if (dbTombUser.getUserInfo().getServerId() == choosePvpUserInfo.getDbTombUser().getUserInfo().getServerId() && choosePvpUserInfo.getDbTombUser().isFullHp()) {
                pvpUserInfos2.add(choosePvpUserInfo);
            }

            if (dbTombUser.getUserInfo().getServerId() != choosePvpUserInfo.getDbTombUser().getUserInfo().getServerId() && !choosePvpUserInfo.getDbTombUser().isFullHp()) {
                pvpUserInfos3.add(choosePvpUserInfo);

            }

            if (dbTombUser.getUserInfo().getServerId() == choosePvpUserInfo.getDbTombUser().getUserInfo().getServerId() && !choosePvpUserInfo.getDbTombUser().isFullHp()) {
                pvpUserInfos4.add(choosePvpUserInfo);

            }
        }

        if (pvpUserInfos1.size() > 0) {
            if (pvpUserInfos1.size() == 1) {
                return pvpUserInfos1.get(0).getDbTombUser().getUserId();
            }
            Random random = new Random();
            int i = random.nextInt(pvpUserInfos1.size());
            return pvpUserInfos1.get(i).getDbTombUser().getUserId();
        }
        if (pvpUserInfos2.size() > 0) {
            if (pvpUserInfos2.size() == 1) {
                return pvpUserInfos2.get(0).getDbTombUser().getUserId();
            }
            Random random = new Random();
            int i = random.nextInt(pvpUserInfos2.size());
            return pvpUserInfos2.get(i).getDbTombUser().getUserId();
        }
        if (pvpUserInfos3.size() > 0) {
            if (pvpUserInfos3.size() == 1) {
                return pvpUserInfos3.get(0).getDbTombUser().getUserId();
            }
            Random random = new Random();
            int i = random.nextInt(pvpUserInfos3.size());
            return pvpUserInfos3.get(i).getDbTombUser().getUserId();
        }
        if (pvpUserInfos4.size() > 0) {
            if (pvpUserInfos4.size() == 1) {
                return pvpUserInfos4.get(0).getDbTombUser().getUserId();
            }
            Random random = new Random();
            int i = random.nextInt(pvpUserInfos4.size());
            return pvpUserInfos4.get(i).getDbTombUser().getUserId();
        }

        return 0;
    }


    public List<Tomb.CoordinateTemp> getDoorList() {
        List<Tomb.CoordinateTemp> list = new ArrayList<>();
        for (DoorInfo doorInfo : this.dbTombMaze.getMaze().getDoorInfoMap().values()) {
            Tomb.CoordinateTemp.Builder builder = Tomb.CoordinateTemp.newBuilder();
            builder.setFloor(this.floor);
            builder.setRow(doorInfo.getX());
            builder.setColumn(doorInfo.getY());
            list.add(builder.build());
        }
        return list;
    }


    public void refundUnAttackDigUserEnergy(DbTombPosition dbTombPosition) {
        for (DigUserInfo digUserInfo : dbTombPosition.getDigUnionUserMap().values()) {

            boolean b = dbTombPosition.getEventInfoMap().containsKey(digUserInfo.getUserId());
            if (b) {
                continue;
            }
            DbTombUser dbTombUser = this.activity.getDbData().getDbTombUser(digUserInfo.getUserId());
            if (dbTombUser == null) {
                continue;
            }
            ActivityTombEvent activityTombEvent = this.getConfig().getEvent(dbTombPosition.getEventId());
            dbTombUser.addEnergy(activityTombEvent.getConsumeEnergy());

            //日志
//            DbTombLog dbTombLog = DbTombLog.newInstance();
//            dbTombLog.setUid(String.valueOf(dbTombUser.getUserId()));
//            dbTombLog.setFloor(this.floor);
//            dbTombLog.setFromUserId(dbTombUser.getUserId());
//            dbTombLog.setLogEnum(Tomb.TombLogEnum.TombLogEnum_Energy_Un_Attack_VALUE);
//            dbTombLog.setEventId(activityTombEvent.getId());
//            dbTombLog.setValue1(activityTombEvent.getNpcId());
//            dbTombLog.setEnergyChange(activityTombEvent.getConsumeEnergy());
//            dbTombLog.setEnergy(dbTombUser.getEnergy(this.getConfig().getConfig()));
//            dbTombLog.setX(dbTombPosition.getX());
//            dbTombLog.setY(dbTombPosition.getY());
//            dbTombLog.setDescription("未攻击，反还体力");
//            this.activity.getTombLog().add(dbTombLog);
        }
    }

    public void handleAttackScore(long attack, long maxHp, ActivityTombEvent activityTombEvent, Property property, DbTombUser dbTombUser) {
        double addScore = (double) attack / (double) maxHp * (double) activityTombEvent.getScore().get(0);

        addScore = Math.ceil(addScore);
        long addScoreLong = (long) addScore;

        double addUnionScore = (double) attack / (double) maxHp * (double) activityTombEvent.getScore().get(1);
        addUnionScore = Math.ceil(addUnionScore);
        long addUnionScoreLong = (long) addUnionScore;
        if (addScoreLong > 0) {
            property.addProperty(this.getConfig().getConfig().getTOMB_SCORE_ITEM_ID(), BigInteger.valueOf(addScoreLong));
        }
        if (addUnionScoreLong > 0) {
            property.addProperty(this.getConfig().getConfig().getTOMB_GUILD_SCORE_ITEM_ID(), BigInteger.valueOf(addUnionScoreLong));
        }
    }


    public void attackPvpTombUserPush(DbTombUser dbTombUser, DbTombUser pvpDbTombUser, boolean alive, long attack, DbTombPosition dbTombPosition, boolean goDownstairs) {
        Map<String, DbTombPosition> stringDbTombPositionMap = this.activity.getDbData().getDbTombPositionMap(dbTombUser.getGroupId(), this.floor);
        for (DbTombPosition dbTombPosition1 : stringDbTombPositionMap.values()) {
            if (dbTombPosition1.getDone() == 1) {
                continue;
            }
            if (dbTombPosition1.geteType() != Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE) {
                continue;
            }
            if (dbTombPosition1.getKey().equals(dbTombPosition.getKey())) {
                continue;
            }
            if (dbTombPosition1.getPvpUserId() != pvpDbTombUser.getUserId()) {
                continue;
            }
            Position position = this.getRealPosition(dbTombPosition1.getX(), dbTombPosition1.getY());
            if (position == null) {
                continue;
            }
            if (!alive) {
                if (dbTombPosition1.getDigUnionUserMap() != null) {
                    if (pvpDbTombUser.getPvpUnionChooseMap() != null) {
                        for (Map.Entry<String, DigUserInfo> digUserInfoEntry : dbTombPosition1.getDigUnionUserMap().entrySet()) {
                            pvpDbTombUser.getPvpUnionChooseMap().remove(digUserInfoEntry.getKey());
                        }
                    }
                }
                position.setpEnum(Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE);
                dbTombPosition1.setDone(1);
                this.updateGrip(position);
            } else {
                position.refreshTimestamp();
            }
            String key = String.format("%d_%d_%d_%d", dbTombUser.getGroupId(), this.getFloor(), position.getRow(), position.getColumn());
            this.eventBattleSyncPush(dbTombUser, attack, pvpDbTombUser.getHp(), key, goDownstairs);
        }

    }

    public Set<Integer> randPartnerList(DbTombUser dbTombUser) {
        int p1 = this.getConfig().getConfig().getTOMB_ADD_EVENT_REFRESH_RULE().get(0);
        int p2 = this.getConfig().getConfig().getTOMB_ADD_EVENT_REFRESH_RULE().get(1);
        int p3 = this.getConfig().getConfig().getTOMB_ADD_EVENT_REFRESH_RULE().get(2);
        int p4 = this.getConfig().getConfig().getTOMB_ADD_EVENT_REFRESH_RULE().get(3);


        ActivityTombEvent activityTombEvent = this.getConfig().getEvents(1).get(0);
        int limit = activityTombEvent.getParam1().get(3);
        int randNum = activityTombEvent.getParam1().get(2);
        Set<Integer> set = new HashSet<>();
        if (dbTombUser.getPartnerInfoMap().size() <= randNum) {
            for (PartnerInfo partnerInfo : dbTombUser.getPartnerInfoMap().values()) {
                PartnerUpgradeInfo partnerUpgradeInfo = dbTombUser.acquirePartnerUpgradeInfo(partnerInfo.getId());
                if (partnerUpgradeInfo.getTimes() >= limit) {
                    continue;
                }
                set.add(partnerInfo.getId());
            }
            return set;
        }

        int total = 0;
        Map<Integer, Integer> partnerWeight = new HashMap<>();
        for (PartnerInfo partnerInfo : dbTombUser.getPartnerInfoMap().values()) {
            PartnerUpgradeInfo partnerUpgradeInfo = dbTombUser.acquirePartnerUpgradeInfo(partnerInfo.getId());
            if (partnerUpgradeInfo.getTimes() >= limit) {
                continue;
            }
            double step1 = (double) p2 / (double) p4;
            double step2 = Math.pow(step1, partnerUpgradeInfo.getTimes());
            double step3 = step2 * p1;
            double max = Math.max(step3, p3);
            max = Math.ceil(max);
            int result = (int) max;

            partnerWeight.put(partnerInfo.getId(), result);
            total = total + result;
        }
        //如果总供可以随的数量，不足需要的数量，就把所有可以随的门客都返回
        if (partnerWeight.size() <= randNum) {
            for (Map.Entry<Integer, Integer> entry : partnerWeight.entrySet()) {
                set.add(entry.getKey());
            }
            return set;
        }

        int whileTimes = 0;
        Random random = new Random();
        while (set.size() < randNum) {
            //随100次，还不满足的话，就退出了
            if (whileTimes >= 100) {
                break;
            }
            whileTimes++;

            int i = random.nextInt(total);
            for (Map.Entry<Integer, Integer> entry : partnerWeight.entrySet()) {
                if (i < entry.getValue()) {
                    set.add(entry.getKey());
                    break;
                } else {
                    i = i - entry.getValue();
                }
            }

            if (set.size() >= partnerWeight.size()) {
                break;
            }
        }
        return set;
    }

    public List<Coordinate> getStandPositionAroundCoordinate(Coordinate start, int x, int y) {
        List<Coordinate> list = new ArrayList<>();
        Position position = this.getRealPosition(x, y);
        if (position != null && position.getFlag() == 1 && position.getpEnum() == Tomb.PositionEnum.POSITION_EVENT_VALUE) {
            for (int i = -2; i < 1; i++) {
                for (int j = -2; j < 1; j++) {
                    Coordinate coordinate = Coordinate.newInstance(position.getRow() + i, position.getColumn() + j);
                    coordinate.setDistance(Math.abs(coordinate.getX() - start.getX()) + Math.abs(coordinate.getY() - start.getY()));
                    list.add(coordinate);
                }
            }
            list.sort(Comparator.comparing(Coordinate::getDistance));
            return list;
        }
        Coordinate coordinate = Coordinate.newInstance(x, y);
        list.add(coordinate);
        return list;
    }

    public Map<String, Position> getBuffEventMap() {
        return buffEventMap;
    }


    public Position fullBigEvent(Position position) {
        if (position.getFlag() == 1) {
            return position;
        }

        if (position.getpRelation().length() > 0) {
            Position position1 = this.getPosition(position.getpRelation());
            if (position1 == null) {
                return null;
            }
            if (position1.getFlag() == 1 && position1.geteType() == 0) {
                return position1;
            }
        }
        return null;
    }

    public void eventDone(DbTombPosition dbTombPosition, Position position) {
        if (dbTombPosition != null) {
            dbTombPosition.setDone(1);
            dbTombPosition.refreshUpdateTime();
        }
        position.setpEnum(Tomb.PositionEnum.POSITION_EVENT_DONE_VALUE);
        this.updateGrip(position);
    }

    public ActivityTombEvent randomActivityTombEvent(boolean canBigEvent, boolean finalBoss, DbTombMaze dbTombMaze) {


        int totalEvent = 0;
        int totalBigEvent = 0;

        int surplusWaitEvent = 0;
        int surplusWaitBigEvent = 0;

        List<EventWeight> bigEventWeights = new ArrayList<>();
        List<EventWeight> eventWeights = new ArrayList<>();
        if (this.canExploredEliteNpc()) {
            if (finalBoss) {
                EventWeight eventWeight = new EventWeight();
                ActivityTombEvent activityTombEvent = this.getConfig().getBoss(this.floor);
                eventWeight.setEventId(activityTombEvent.getId());
                eventWeight.setWeight(1);
                bigEventWeights.add(eventWeight);
            } else {
                EventWeight eventWeight = new EventWeight();
                eventWeight.setEventId(this.dbTombMaze.getEliteEventId());
                eventWeight.setWeight(1);
                bigEventWeights.add(eventWeight);
            }
        }
        for (EventInfo eventInfo : dbTombMaze.getEventInfoList()) {
            int eventId = eventInfo.getEventId();
            int num = eventInfo.getGenerateNum();
            if (num == 0) {
                continue;
            }
            ActivityTombEvent activityTombEvent = this.getConfig().getEvent(eventId);
            if (activityTombEvent.getEventType() == 1) {
                continue;
            }
            if (activityTombEvent.isElite()) {
                continue;
            }

            if (activityTombEvent.isFinalBoss()) {
                continue;
            }

            EventWeight eventWeight = new EventWeight();
            if (activityTombEvent.isBigEvent()) {
                totalBigEvent = totalBigEvent + num;
                int i = this.dbTombMaze.acquireExploredNum(eventId);
                eventWeight.setEventId(eventId);
                int weight = num - i;
                if (weight <= 0) {
                    continue;
                }
                surplusWaitBigEvent = surplusWaitBigEvent + weight;
                eventWeight.setWeight(weight);
                bigEventWeights.add(eventWeight);
            } else {
                totalEvent = totalEvent + num;
                int i = this.dbTombMaze.acquireExploredNum(eventId);
                eventWeight.setEventId(eventId);
                int weight = num - i;
                if (weight <= 0) {
                    continue;
                }
                surplusWaitEvent = surplusWaitEvent + weight;
                eventWeight.setWeight(weight);
                eventWeights.add(eventWeight);
            }
        }


        if (canBigEvent) {
            int surplusBigEvent = this.dbTombMaze.getMaze().getTotalBigEventNum() - this.dbTombMaze.getBrakeBigGripNum();

            if (this.canExploredEliteNpc()) {
                if (surplusBigEvent <= 3) {
                    if (finalBoss) {
                        return this.getConfig().getBoss(this.floor);
                    } else {
                        return this.getElite();
                    }
                }
            }

            if (surplusWaitBigEvent > 0) {
                if (surplusBigEvent > surplusWaitBigEvent) {
                    Random random = new Random();
                    int i = random.nextInt(surplusBigEvent);
                    if (i >= surplusWaitBigEvent) {
                        canBigEvent = false;
                    }
                }

            } else {
                canBigEvent = false;
            }
        }

        if (canBigEvent) {
            Random random = new Random();
            if (surplusWaitBigEvent > 0) {
                int i = random.nextInt(surplusWaitBigEvent);
                for (EventWeight eventWeight : bigEventWeights) {
                    if (eventWeight.getWeight() <= 0) {
                        continue;
                    }
                    if (i < eventWeight.getWeight()) {
                        return this.getConfig().getEvent(eventWeight.getEventId());
                    } else {
                        i = i - eventWeight.getWeight();
                    }
                }
            }

        } else {
            Random random = new Random();
            if (surplusWaitEvent > 0) {
                int i = random.nextInt(surplusWaitEvent);
                for (EventWeight eventWeight : eventWeights) {
                    if (eventWeight.getWeight() <= 0) {
                        continue;
                    }
                    if (i < eventWeight.getWeight()) {
                        return this.getConfig().getEvent(eventWeight.getEventId());
                    } else {
                        i = i - eventWeight.getWeight();
                    }
                }
            }
        }
        return this.randomEvent(dbTombMaze);
    }


    public ActivityTombEvent randomEvent(DbTombMaze dbTombMaze) {
        int totalEvent = 0;
        List<EventWeight> eventWeights = new ArrayList<>();
        for (EventInfo eventInfo : dbTombMaze.getEventInfoList()) {
            int eventId = eventInfo.getEventId();
            int num = eventInfo.getGenerateNum();
            if (num == 0) {
                continue;
            }
            ActivityTombEvent activityTombEvent = this.getConfig().getEvent(eventId);
            if (activityTombEvent.getEventType() != Tomb.EventEnum.EVENT_CHOOSE_VALUE) {
                continue;
            }
            totalEvent = totalEvent + num;
            EventWeight eventWeight = new EventWeight();
            eventWeight.setEventId(eventId);
            eventWeight.setWeight(num);
            eventWeights.add(eventWeight);

        }
        Random random = new Random();
        int i = random.nextInt(totalEvent);
        for (EventWeight eventWeight : eventWeights) {
            if (eventWeight.getWeight() <= 0) {
                continue;
            }
            if (i < eventWeight.getWeight()) {
                return this.getConfig().getEvent(eventWeight.getEventId());
            } else {
                i = i - eventWeight.getWeight();
            }
        }
        return null;
    }


    public ActivityTombEvent randomNpcBattle(DbTombMaze dbTombMaze) {
        int totalEvent = 0;
        List<EventWeight> eventWeights = new ArrayList<>();
        for (EventInfo eventInfo : dbTombMaze.getEventInfoList()) {
            int eventId = eventInfo.getEventId();
            int num = eventInfo.getGenerateNum();
            if (num == 0) {
                continue;
            }
            ActivityTombEvent activityTombEvent = this.getConfig().getEvent(eventId);
            if (activityTombEvent.getEventType() != Tomb.EventEnum.EVENT_NPC_BATTLE_VALUE) {
                continue;
            }
            if (activityTombEvent.isBigEvent()) {
                continue;
            }

            if (activityTombEvent.isFinalBoss()) {
                continue;
            }
            totalEvent = totalEvent + num;
            EventWeight eventWeight = new EventWeight();
            eventWeight.setEventId(eventId);
            eventWeight.setWeight(num);
            eventWeights.add(eventWeight);

        }
        Random random = new Random();
        int i = random.nextInt(totalEvent);
        for (EventWeight eventWeight : eventWeights) {
            if (eventWeight.getWeight() <= 0) {
                continue;
            }
            if (i < eventWeight.getWeight()) {
                return this.getConfig().getEvent(eventWeight.getEventId());
            } else {
                i = i - eventWeight.getWeight();
            }
        }
        return null;
    }

    public boolean canExploredEliteNpc() {
        if (!StringUtil.isNullOrEmpty(this.getDbTombMaze().getEliteNpcEvent())) {
            return false;
        }
        int totalBigEvent = this.dbTombMaze.getMaze().getTotalBigEventNum();
        int a = (int) ((double) totalBigEvent / (double) 1000 * (double) this.getConfig().getConfig().getTOMB_ELITE_TRIGGER_CONDITION());
        if (this.dbTombMaze.getBrakeBigGripNum() > a) {
            return true;
        }
        return false;
    }


    public boolean costEnergy(DbTombUser dbTombUser, int costEnergy, int eventId) {
        ActivityTombFloor activityTombFloor = this.getConfig().getFloor(this.floor);
        int energy = activityTombFloor.getEnergy();
        if (costEnergy > 0) {
            energy = costEnergy;
        }

        int tomb_energy_limit = this.getConfig().getConfig().getTOMB_ENERGY_LIMIT();
        if (dbTombUser.getEnergy(this.getConfig().getConfig()) >= tomb_energy_limit) {
            dbTombUser.setEnergyUpdateTime(System.currentTimeMillis());
            dbTombUser.refreshUpdateTime();
        }
        return dbTombUser.costEnergy(energy, eventId);
    }

    public void recoverEnergy(DbTombUser dbTombUser) {
        ActivityTombFloor activityTombFloor = this.getConfig().getFloor(this.floor);
        int energy = activityTombFloor.getEnergy();
        dbTombUser.addEnergy(energy);
    }

    public boolean checkNeedCostEnergy(DbTombPosition dbTombPosition, DbTombUser dbTombUser) {
        if (!dbTombPosition.isAlive()) {
            return false;
        }

        if (dbTombPosition.acquireUnionDigUser(dbTombUser.getUserInfo().getUnionUid()) == dbTombUser.getUserId()) {
            if (dbTombPosition.acquireEventInfo(dbTombUser.getUserId()).getAttackTimes() == 0) {
                return false;
            }
        }
        return true;
    }

    public boolean checkPVPNeedCostEnergy(DbTombUser pvpTombUser, DbTombPosition dbTombPosition, DbTombUser dbTombUser) {
        if (!pvpTombUser.isAlive()) {
            return false;
        }
        if (dbTombPosition.acquireDigUser() != dbTombUser.getUserId()) {
            return true;
        }

        if (dbTombPosition.acquireEventInfo(dbTombUser.getUserId()).getAttackTimes() > 0) {
            return true;
        }
        return false;
    }

    public Coordinate getBirthplace(DbTombUser dbTombUser) {
        DoorInfo doorInfo = this.getDbTombMaze().getMaze().acquireDoorInfo(dbTombUser.getUserInfo().getUnionUid());
        int x = doorInfo.getX();
        int y = doorInfo.getY();
        if (x == 0) {
            x = 1;
        }
        if (y == 0) {
            y = 1;
        }

        Coordinate coordinate = Coordinate.newInstance(x, y);
        return coordinate;
    }


    public ActivityTombEvent getElite() {
        int eventId = this.getDbTombMaze().getEliteEventId();
        ActivityTombEvent activityTombEvent = this.getConfig().getEvent(eventId);
        return activityTombEvent;
    }

    public void fillPositionTemp(DbTombPosition dbTombPosition, DbTombUser dbTombUser, Tomb.PositionTemp.Builder positionTempBuilder) {
        positionTempBuilder.setRow(dbTombPosition.getX());
        positionTempBuilder.setColumn(dbTombPosition.getY());
        positionTempBuilder.setEnum(dbTombPosition.getpEnum());
        positionTempBuilder.setEventEnum(dbTombPosition.geteType());

    }


    public List<Tomb.TombUnionHelpInfoTemp> getTombUnionHelpList(DbTombUser dbTombUser) {
        List<Tomb.TombUnionHelpInfoTemp> list = new ArrayList<>();

        Map<String, DbTombPosition> dbTombPositionMap = this.getActivity().getActivityUnion(dbTombUser.getUserInfo().getUnionUid()).getDbTombPositionMap(this.getFloor());
        //先获取战斗的事件

        List<Integer> eventList = new ArrayList<>();
        eventList.add(2);
        eventList.add(3);
        eventList.add(4);
        eventList.add(5);
        for (DbTombPosition dbTombPosition : dbTombPositionMap.values()) {
            if (dbTombPosition.getDone() == 1) {
                continue;
            }

            if (dbTombPosition.geteType() == Tomb.EventEnum.EVENT_ENTER_VALUE) {
                continue;
            }

            Position position = this.getPosition(dbTombPosition.getX(), dbTombPosition.getY());
            if (position == null || position.getpEnum() != Tomb.PositionEnum.POSITION_EVENT_VALUE) {
                continue;
            }

            if (!eventList.contains(dbTombPosition.geteType())) {
                continue;
            }


            DbTombUser digDbTombUser = this.activity.getDbData().getDbTombUser(dbTombPosition.acquireUnionDigUser(dbTombUser.getUserInfo().getUnionUid()));
            if (digDbTombUser == null) {
                continue;
            }
            Tomb.TombUnionHelpInfoTemp.Builder temp = Tomb.TombUnionHelpInfoTemp.newBuilder();
            temp.setRow(dbTombPosition.getX());
            temp.setColumn(dbTombPosition.getY());
            temp.setName(digDbTombUser.getUserInfo().getNickName());
            temp.setHp(dbTombPosition.getCurrentHp());
            temp.setMaxHp(dbTombPosition.getMaxHp());
            temp.setFoundTimestamp(dbTombPosition.getCreateTime());
            temp.setEvenType(dbTombPosition.geteType());
            temp.setEventFloor(dbTombPosition.getFloor());
            temp.setEventId(dbTombPosition.getEventId());
            if (dbTombPosition.geteType() == Tomb.EventEnum.EVENT_PVP_BATTLE_VALUE) {
                DbTombUser pvpDbTombUser = this.activity.getDbData().getDbTombUser(dbTombPosition.getPvpUserId());
                temp.setHp(pvpDbTombUser.getHp());
                temp.setMaxHp(pvpDbTombUser.getMaxHp());
                temp.setPvpUserInfo(pvpDbTombUser.toPvpUserInfoTempBuilder());
                PositionInfo positionInfo = dbTombPosition.acquireEventInfo(dbTombUser.getUserId());
                temp.setLastAttackTimestamp(positionInfo.getTimestamp() * 1000);

            } else {
                ActivityTombEvent activityTombEvent = this.activity.getConfig().getEvent(dbTombPosition.getEventId());
                temp.setNpcId(activityTombEvent.getNpcId());
            }
            temp.setTimestamp(dbTombPosition.getCreateTime());
            list.add(temp.build());
        }


        return list;
    }


    public List<Tomb.TombMazeEliteNpcLogTemp> getEliteNpcLogList() {
        List<Tomb.TombMazeEliteNpcLogTemp> list = new ArrayList<>();
        DbTombPosition dbTombPosition = this.getDbTombPosition(this.getDbTombMaze().getEliteNpcEvent());
        if (dbTombPosition == null) {
            return list;
        }
        ArrayList<PositionInfo> positionInfos = new ArrayList<>(dbTombPosition.getEventInfoMap().values());
        positionInfos.sort(Comparator.comparing(PositionInfo::getAttack).reversed());
        int rank = 1;
        for (PositionInfo positionInfo : positionInfos) {
            Tomb.TombMazeEliteNpcLogTemp.Builder temp = Tomb.TombMazeEliteNpcLogTemp.newBuilder();
            DbTombUser dbTombUser1 = activity.getDbData().getDbTombUser(positionInfo.getUserId());
            temp.setUserInfo(dbTombUser1.toPlayerBaseTempBuilder());
            temp.setUserId(dbTombUser1.getUserId());
            temp.setRank(rank);
            list.add(temp.build());
            rank++;
        }
        return list;
    }

    public boolean canRewardEliteEvent(List<Tomb.TombMazeEliteNpcLogTemp> list, DbTombUser dbTombUser, DbTombPosition dbTombPosition) {
        if (dbTombPosition.isAlive()) {
            return false;
        }
        PositionInfo positionInfo = dbTombPosition.getEventInfoMap().get(dbTombUser.getUserId());
        if (positionInfo == null) {
            return false;
        }
        if (positionInfo.isReward()) {
            return false;
        }
        int type = eGamePlayerEventType.TombEliteAttackRankReward.getValue();
        ActivityTombEvent activityTombEvent = activity.getConfig().getEvent(dbTombPosition.getEventId());
        if (activityTombEvent.getEventType() == Tomb.EventEnum.EVENT_BOSS_BATTLE_VALUE) {
            type = eGamePlayerEventType.TombBossAttackRankReward.getValue();
        }
        for (Tomb.TombMazeEliteNpcLogTemp tombMazeEliteNpcLogTemp : list) {
            if (tombMazeEliteNpcLogTemp.getUserId() == dbTombUser.getUserId()) {
                for (ActivityTombRank activityTombRank : activity.getConfig().getRanks()) {
                    if (activityTombRank.getType() == type) {
                        if (tombMazeEliteNpcLogTemp.getRank() >= activityTombRank.getParams().get(0) && tombMazeEliteNpcLogTemp.getRank() <= activityTombRank.getParams().get(1)) {
                            return true;
                        }
                    }
                }
                break;
            }
        }
        return false;
    }

    /**
     * 合并各个区域的已探索集合
     */

    public void pathMerge() {
        this.pathMergeLock.lock();
        try {

            Set<String> doneSet = new HashSet<>();
            for (Map.Entry<String, Set<String>> e : this.pathAreaMap.entrySet()) {
                for (Map.Entry<String, Set<String>> e1 : this.pathAreaMap.entrySet()) {

                    if (e.getValue() == e1.getValue()) {
                        continue;
                    }
                    if (doneSet.contains(e.getKey() + "_" + e1.getKey())) {
                        continue;
                    }
                    doneSet.add(e.getKey() + "_" + e1.getKey());
                    doneSet.add(e1.getKey() + "_" + e.getKey());

                    Set<String> result = new HashSet<>(e.getValue());
                    result.retainAll(e1.getValue());
                    if (result.size() > 0) {
                        result.clear();
                        e.getValue().addAll(e1.getValue());
                        this.pathAreaMap.put(e1.getKey(), e.getValue());
                    }
                }
            }
        } finally {
            this.pathMergeLock.unlock();
        }
    }


    /**
     * 初始化各个区已探索的
     */
    public void initPathAreaSet() {
        this.pathMergeLock.lock();
        try {
            for (DoorInfo doorInfo : this.getDbTombMaze().getMaze().getDoorInfoMap().values()) {
                String positionKey = this.getPositionKey(doorInfo.getX(), doorInfo.getY());
                HashSet<String> areaSet = new HashSet<>();
                areaSet.add(positionKey);
                Set<String> whatAddSet = new HashSet<>();
                this.addPathToSet(areaSet, whatAddSet, positionKey);
                areaSet.addAll(whatAddSet);
                this.pathAreaMap.put(positionKey, areaSet);
            }
        } finally {
            this.pathMergeLock.unlock();
        }
    }

    public void printPathAreaSet() {
        int maxRow = this.getDbTombMaze().getMaze().getMaxRow();
        int maxColumn = this.getDbTombMaze().getMaze().getMaxColumn();
        int[][] areaGrip;
        areaGrip = new int[maxRow][];
        for (int i = 0; i < areaGrip.length; i++) {
            areaGrip[i] = new int[maxColumn];
        }

        for (int i = 0; i < maxRow; i++) {
            for (int j = 0; j < maxColumn; j++) {
                int index = this.getAreaSetKey(String.format("%d_%d", i, j));
                areaGrip[i][j] = index;
                System.out.printf("%d ", index);
            }
            System.out.print("\n");
        }
        System.out.println("------------------------------------");
    }

    /**
     * @param waitAddSet  待添加的集合
     * @param positionKey 探索的位置
     */
    public void addPathToSet(Set<String> areaSet, Set<String> waitAddSet, String positionKey) {
        Set<String> waitProcessSet = new HashSet<>(); //待处理的集合
        Set<String> removeSet = new HashSet<>();
        String targetPositionKey = positionKey;
        waitProcessSet.add(positionKey);
        Set<String> allPathAreaSet = this.getAllPathAreaSet();
        while (this.waitAddPathArea(areaSet, allPathAreaSet, waitProcessSet, waitAddSet, targetPositionKey).size() > 0) {
            targetPositionKey = "";
            for (String s1 : waitProcessSet) {
                removeSet.add(s1);
                waitAddSet.add(s1);
                Position position = this.getRealPosition(s1);
                if (position == null || position.canThrough()) {
                    targetPositionKey = s1;
                    break;
                }
            }
            waitProcessSet.removeAll(removeSet);
            removeSet.clear();
        }
    }


    /**
     * 查找某个点周围，可以添加的位置到集合
     *
     * @param waitProcessSet 待处理的集合
     * @param waitAddSet     待添加的集合
     * @param key            待处理的位置
     * @return
     */
    public Set<String> waitAddPathArea(Set<String> areaSet, Set<String> allAreaSet, Set<String> waitProcessSet, Set<String> waitAddSet, String key) {
        if (key.length() == 0) {
            return waitProcessSet;
        }
        String[] split = key.split("_");
        int x = Integer.parseInt(split[0]);
        int y = Integer.parseInt(split[1]);
        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if (Math.abs(i) == Math.abs(j)) {
                    continue;
                }
                int _x = x + i;
                int _y = y + j;
                if (_x < 0 || _y < 0) {
                    continue;
                }
                String positionKey = this.getPositionKey(_x, _y);
                Position realPosition = this.getRealPosition(_x, _y);
                if (realPosition != null && !realPosition.canThrough()) {
                    continue;
                }
                if (waitProcessSet.contains(positionKey)) {
                    continue;
                }
                if (waitAddSet.contains(positionKey)) {
                    continue;
                }
                if (areaSet.contains(positionKey)) {
                    continue;
                } else {
                    if (allAreaSet.contains(positionKey)) {
                        waitAddSet.add(positionKey);
                        continue;
                    }
                }
                waitProcessSet.add(positionKey);
            }
        }
        return waitProcessSet;
    }


    /**
     * 把已探索的格子，加入到集合进去
     *
     * @param start
     * @param x
     * @param y
     */
    public void addPathToAreaSet(Coordinate start, int x, int y) {
        if (start.getX() == 0 && start.getY() == 0) {
            return;
        }
        String positionKey = this.getPositionKey(x, y);
        Position realPosition = this.getRealPosition(x, y);
        if (realPosition != null && !realPosition.canThrough()) {
            return;
        }
        this.pathMergeLock.lock();
        try {
            Set<String> areaSet = this.getAreaSet(start.getX(), start.getY());
            Set<String> waitAddSet = new HashSet<>();
            this.addPathToSet(areaSet, waitAddSet, positionKey);
            areaSet.addAll(waitAddSet);
        } catch (Exception e) {
            logger.error("addPathToAreaSet error start{},{}, position {}, {}", start.getX(), start.getY(), x, y);
        } finally {
            this.pathMergeLock.unlock();
        }

//        this.printPathAreaSet();
    }


    public Set<String> getAreaSet(int x, int y) {
        for (Set<String> value : this.pathAreaMap.values()) {
            String positionKey = this.getPositionKey(x, y);
            if (value.contains(positionKey)) {
                return value;
            }
        }
        return null;
    }

    public int getAreaSetKey(String key) {
        List<Set<String>> list = new ArrayList<>();
        for (Set<String> value : this.pathAreaMap.values()) {
            list.add(value);
        }
        int index = 1;
        for (Set<String> strings : list) {
            if (strings.contains(key)) {
                return index;
            }
            index++;
        }
        return 0;
    }

    /**
     * 目前位置是否在同一个区域
     *
     * @param dbTombUser
     * @param coordinate
     * @return
     */
    public boolean inSamePathArea(DbTombUser dbTombUser, Coordinate coordinate) {
        Set<String> areaSet = this.getAreaSet(dbTombUser.getX(), dbTombUser.getY());
        if (areaSet == null) {
            return false;
        }
        if (areaSet.contains(coordinate.getKey())) {
            return true;
        }
        return false;
    }


    public int getToEndDistance(DbTombUser dbTombUser, Position position) {
        int x = Math.abs(dbTombUser.getX() - position.getRow());
        int y = Math.abs(dbTombUser.getY() - position.getColumn());
        return x + y;
    }

    public int getToEndDistance(DbTombUser dbTombUser, Coordinate coordinate) {
        int x = Math.abs(dbTombUser.getX() - coordinate.getX());
        int y = Math.abs(dbTombUser.getY() - coordinate.getY());
        return x + y;
    }

    public Lock getPositionLock(int lockIndex) {
        if (!this.positionLockMap.containsKey(lockIndex)) {
            this.positionLockMap.put(lockIndex, new ReentrantLock());
        }
        return this.positionLockMap.get(lockIndex);
    }


    public Map<String, Coordinate> getCanStandPositionAroundCoordinate(DbTombUser dbTombUser, int x, int y) {
        Map<String, Coordinate> map = new HashMap<>();
        Coordinate start = Coordinate.newInstance(dbTombUser.getX(), dbTombUser.getY());
        List<Coordinate> aroundCoordinate = this.getStandPositionAroundCoordinate(start, x, y);
        for (Coordinate coordinate : aroundCoordinate) {
            for (int i = -1; i <= 1; i++) {
                for (int j = -1; j <= 1; j++) {
                    if (Math.abs(i) == Math.abs(j)) {
                        continue;
                    }
                    int _x = coordinate.getX() + i;
                    int _y = coordinate.getY() + j;
                    Position realPosition = this.getRealPosition(_x, _y);
                    if (realPosition == null || this.canStand(dbTombUser, realPosition)) {
                        Coordinate coordinate1 = Coordinate.newInstance(_x, _y);
                        int toEndDistance = this.getToEndDistance(dbTombUser, coordinate1);
                        coordinate1.setDistance(toEndDistance);
                        map.put(coordinate1.getKey(), coordinate1);
                    }
                }
            }
        }
        return map;
    }

    public Set<String> getAllPathAreaSet() {
        Set<String> allSet = new HashSet<>();
        for (Set<String> set : this.pathAreaMap.values()) {
            allSet.addAll(set);
        }
        return allSet;
    }

    public Tomb.TombNpcInfoPush.Builder getNpcInfo() {
        Tomb.TombNpcInfoPush.Builder builder = Tomb.TombNpcInfoPush.newBuilder();
        //这里增加一下容错，避免明明地图上没有大格子可以挖了，还显示有精英怪的情况；
        int totalBigEventNum = this.dbTombMaze.getMaze().getTotalBigEventNum();
        int brakeBigGripNum = this.dbTombMaze.getBrakeBigGripNum();
        if (totalBigEventNum - brakeBigGripNum <= 1) {
            return builder;
        }
        for (EventInfo eventInfo : this.dbTombMaze.getEventInfoList()) {
            ActivityTombEvent activityTombEvent = this.getConfig().getEvent(eventInfo.getEventId());
            if (activityTombEvent.getEventType() != Tomb.EventEnum.EVENT_NPC_BATTLE_VALUE) {
                continue;
            }
            if (!activityTombEvent.isBigEvent()) {
                continue;
            }
            Tomb.TombNpcInfo.Builder temp = Tomb.TombNpcInfo.newBuilder();
            temp.setNpcId(activityTombEvent.getNpcId());
            temp.setNum(eventInfo.getGenerateNum() - eventInfo.getDoneNum());
            builder.addInfo(temp);

        }
        return builder;
    }


    public void npcInfoPush() {
        Tomb.TombNpcInfoPush.Builder npcInfo = this.getNpcInfo();
        Map<Long, Tomb.TombNpcInfoPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();
        List<HeartbeatInfo> heartbeatInfoList = this.getActivity().getHeartbeat().getList(this.dbTombMaze.groupId);
        for (HeartbeatInfo heartbeatInfo : heartbeatInfoList) {
            if (heartbeatInfo.getFloor() != this.getFloor()) {
                continue;
            }
            if (!toGameReqMap.containsKey(heartbeatInfo.getServerId())) {
                toGameReqMap.put(heartbeatInfo.getServerId(), Tomb.TombNpcInfoPushCrossToGameReq.newBuilder().setResp(npcInfo));
            }
            toGameReqMap.get(heartbeatInfo.getServerId()).addUserId(heartbeatInfo.getUserId());

        }
        toGameReqMap.forEach((serverId, req) -> {
            MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_NPC_INFO_PUSH, this.getActivityId(), 0, req, null);
        });

    }

    public void notifyPush(Tomb.TombNotifyPush.Builder builder) {
        Map<Long, Tomb.TombNotifyPushCrossToGameReq.Builder> toGameReqMap = new HashMap<>();
        UnionActivityGroup unionActivityGroup = Cross2UnionActivityGroupMgr.getGroupData(activity.getActivityInfo().getActivityId(), builder.getGroupId());
        if(unionActivityGroup == null){
            return;
        }
        for (long serverId : unionActivityGroup.getServerSet()) {
            toGameReqMap.put(serverId, Tomb.TombNotifyPushCrossToGameReq.newBuilder().setResp(builder));
        }
        toGameReqMap.forEach((serverId, req) -> {
            MessageHelper.sendToGameServer(serverId, GameProtocol.S_TOMB_NOTIFY_PUSH, this.getActivityId(), 0, req, null);
        });

    }

    /**
     * 玩家脱离卡住，回到门口
     *
     * @param builder
     */
    public void userBreakLock(DbTombUser dbTombUser, Tomb.TombBreakLockRespMsg.Builder builder) {
        Coordinate birthplace = this.getBirthplace(dbTombUser);
        dbTombUser.setX(birthplace.getX());
        dbTombUser.setY(birthplace.getY());
        builder.setRow(dbTombUser.getX());
        builder.setColumn(dbTombUser.getY());
    }

    /**
     * 扣除玩家的协作次数
     *
     * @param dbTombUser 玩家
     * @param value      扣的值
     * @return
     */

    public boolean costAssistTimes(DbTombUser dbTombUser, int value) {
        int assistTimes = dbTombUser.getAssistTimes();
        if (assistTimes <= 0) {
            return false;
        }

        dbTombUser.setAssistTimes(dbTombUser.getAssistTimes() - 1);
        return true;
    }

    /**
     * 检查是否有足够的协助次数
     *
     * @param dbTombUser
     * @param value
     * @return
     */
    public boolean checkIsEnoughAssistTimes(DbTombUser dbTombUser, int value) {
        return dbTombUser.getAssistTimes() >= value;
    }

    public void addExploredNum(DbTombUser dbTombUser, int value) {
        dbTombUser.setExploredNum(dbTombUser.getExploredNum() + value);
        List<Integer> tombAssistsParam = this.getActivity().getConfig().getConfig().getTOMB_ASSISTS_PARAM();
        int p1 = 5;
        int p2 = 1;
        if (tombAssistsParam != null) {
            try {
                p1 = tombAssistsParam.get(0);
                p2 = tombAssistsParam.get(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (dbTombUser.getExploredNum() >= p1) {
            dbTombUser.setExploredNum(dbTombUser.getExploredNum() - p1);
            dbTombUser.setAssistTimes(dbTombUser.getAssistTimes() + p2);
            dbTombUser.refreshUpdateTime();
        }

    }

    public int clearPositionMapData() {
        long currentTimeMillis = System.currentTimeMillis();
        List<String> list = new ArrayList<>();
        for (Position position : this.positionMap.values()) {
            if (!position.canStand()) {
                continue;
            }
            if (currentTimeMillis > position.getTimestamp() + 10 * 60 * 1000) {
                list.add(position.getKey());
            }
        }

        for (String s : list) {
            this.positionMap.remove(s);
        }
        return list.size();
    }
}